
//
//  AudioPlayManager.m
//  AudioPlayDemo
//
//  Created by jianglinjie on 14-1-17.
//  Copyright (c) 2014年 jianglingjie. All rights reserved.
//

#import "AudioPlayManager.h"
#import "FSAudioController.h"
#import "FSAudioStream.h"
#import <AVFoundation/AVFoundation.h>
/**
 * Follow this notification for the audio stream state changes.
 */
extern NSString* const FSAudioStreamStateChangeNotification;
extern NSString* const FSAudioStreamNotificationKey_State;

/**
 * Follow this notification for the audio stream errors.
 */
extern NSString* const FSAudioStreamErrorNotification;
extern NSString* const FSAudioStreamNotificationKey_Error;

/**
 * Follow this notification for the audio stream metadata.
 */
extern NSString* const FSAudioStreamMetaDataNotification;
extern NSString* const FSAudioStreamNotificationKey_MetaData;

NSString* const AudioPlayManagerLoading = @"AudioPlayManagerLoading"; //正在加载

NSString* const AudioPlayManagerPlaying = @"AudioPlayManagerPlaying"; //正在播放
NSString* const AudioPlayManagerPaused  =  @"AudioPlayManagerPaused";  //暂停
NSString* const AudioPlayManagerStopped = @"AudioPlayManagerStopped"; //停止
NSString* const AudioPlayManagerPlayingFinished = @"AudioPlayManagerPlayingFinished"; //播放结束
NSString* const AudioPlayManagerError = @"AudioPlayManagerError";    //错误
NSString* const AudioPlayManagerProgressUpdated = @"AudioPlayManagerProgressUpdated";
@interface AudioPlayManager() <AVAudioPlayerDelegate>
{
    BOOL _isLocal;
}

//@property (nonatomic,strong)  FSAudioController *audioController;
@property (nonatomic,strong)  AVAudioPlayer *audioPlayer;
@property (nonatomic,strong)  NSTimer *progressUpdateTimer;

@end

@implementation AudioPlayManager

+(AudioPlayManager *)shareObject
{
    static dispatch_once_t pred = 0;
    __strong static AudioPlayManager *_sharedObject = nil;
    dispatch_once(&pred, ^{
        _sharedObject = [[self alloc] init];
    });
    return _sharedObject;
}

-(id) init
{
    if(self = [super init])
    {
        _audioController = [[FSAudioController alloc] init];
        

    }
    return self;
}

-(void) postNotification:(NSString *)notificationName
{
    [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:nil userInfo:nil];
}

-(void) setup
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    _audioPlayer.delegate = nil;
    
    if(!_isLocal)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(audioStreamStateDidChange:)
                                                     name:FSAudioStreamStateChangeNotification
                                                   object:nil];
        
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(audioStreamErrorOccurred:)
                                                     name:FSAudioStreamErrorNotification
                                                   object:nil];
        
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(audioStreamMetaDataAvailable:)
                                                     name:FSAudioStreamMetaDataNotification
                                                   object:nil];
    
    }
    else
    {
        _audioPlayer.delegate = self;

    
    }
}

- (void)setAudioURL:(NSString*)url playImmediately:(BOOL)playImmediately isLocal:(BOOL)isLocal
{
    [self stop];
    
    _isLocal = isLocal;
    _currentAudioURL = url;
    if(!isLocal)
    {
        _audioController.url = url;
    }
    else
    {
        NSError* err;
        _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:url] error:&err];

    }
    [self setup];
    
    if(playImmediately)
    {
        [self start];
    }

}

-(void) setEnableProgressUpdateTimer:(BOOL)enableProgressUpdateTimer
{
    _enableProgressUpdateTimer = enableProgressUpdateTimer;
    
    if(_enableProgressUpdateTimer)
    {
        [self openProgressUpdateTimer];
    }
    else
    {
        [self closeProgressUpdateTimer];
    }
}

-(void) openProgressUpdateTimer
{
    [NSObject cancelPreviousPerformRequestsWithTarget:_progressUpdateTimer];
    [_progressUpdateTimer invalidate];
    _progressUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(progressUpdateTimerFired) userInfo:nil repeats:YES];
}

-(void) closeProgressUpdateTimer
{
    [NSObject cancelPreviousPerformRequestsWithTarget:_progressUpdateTimer];
    [_progressUpdateTimer performSelector:@selector(invalidate) withObject:nil afterDelay:1.0];
}

- (void) start
{
    if(self.state == AudioPlayManagerStatePaused)
    {
        [self resume];
        return;
    }

    [self openProgressUpdateTimer];
    
    if(!_isLocal)
    {
        [_audioController play];
    }
    else
    {
        BOOL resultpreplay = [_audioPlayer prepareToPlay];
        BOOL resultplay = [_audioPlayer play];
        
        if(resultpreplay && resultplay)
        {
            self.state = AudioPlayManagerStatePlaying;
        
        }
        else
        {
            self.state = AudioPlayManagerStateError;

        }
    
    }
}

- (void) stop
{
    [self closeProgressUpdateTimer];

    if(!_isLocal)
    {
        [_audioController stop];

    }
    else
    {
        _audioPlayer.currentTime = 0;
        [_audioPlayer stop];
        self.state = AudioPlayManagerStateStopped;
    }
    
}

- (void) pause
{
    [self closeProgressUpdateTimer];

    if(!_isLocal)
    {
        if(self.isPlaying)
        {
            [_audioController pause];
            self.state = AudioPlayManagerStatePaused;
        }
    
    }
    else
    {
        [_audioPlayer pause];
        self.state = AudioPlayManagerStatePaused;
    }

}

- (void)resume
{
    
    
    [self openProgressUpdateTimer];
    
    if(!_isLocal)
    {
        if(self.state == AudioPlayManagerStatePaused)
        {
            [_audioController pause];
            self.state = AudioPlayManagerStatePlaying;
            NSLog(@"after resume currenTime is %d second",_audioController.stream.currentTimePlayed.second);
            
        }
        
    }
    else
    {
        if(self.state == AudioPlayManagerStatePaused)
        {
            BOOL result = [_audioPlayer play];
        
            if(result)
            {
                self.state = AudioPlayManagerStatePlaying;

        
            }
            else
            {
                self.state = AudioPlayManagerStateError;

            }
        }
        

    }
}


- (void) seekToMinutes:(unsigned int) minute Seconds:(unsigned int)second;
{
    if(!_isLocal)
    {
        FSStreamPosition streamPosition ;
        streamPosition.minute = minute;
        streamPosition.second = second;
        [_audioController.stream seekToPosition:streamPosition];
    }
    else
    {
        _audioPlayer.currentTime = minute * 60 + second;
    
    }
}

- (BOOL) isPlaying
{
    if(!_isLocal)
    {
        return _audioController.isPlaying && self.state != AudioPlayManagerStatePaused;
    
    }
    else
    {
        return [_audioPlayer isPlaying];
    }
}


-(CGFloat) duration
{
    if(!_isLocal)
    {
        CGFloat d = _audioController.stream.duration.minute * 60 + _audioController.stream.duration.second;
        return d;
    }
    else
    {
        return _audioPlayer.duration;
    }
}

-(CGFloat) durationPreview
{
    if(!_isLocal)
    {
        CGFloat d = _audioController.stream.duration.minute * 60 + _audioController.stream.duration.second;
        return 30.0;
        //d;
    }
    else
    {
        return _audioPlayer.duration;
    }
}

-(CGFloat) currenPlayedTime
{
    if(!_isLocal)
    {
        CGFloat d = _audioController.stream.currentTimePlayed.minute * 60 + _audioController.stream.currentTimePlayed.second;
        return d;
    }
    else
    {
        return _audioPlayer.currentTime;
    }
}

-(CGFloat) currenPlayedTimePreview
{
    if(!_isLocal)
    {
        CGFloat d = _audioController.stream.currentTimePlayed.minute * 60 + _audioController.stream.currentTimePlayed.second;
        return d;
    }
    else
    {
        return _audioPlayer.currentTime;
    }
}

-(CGFloat) currentPlayedProgressPreview
{
    
    if(!_isLocal)
    {
        if(_audioController.stream.continuous)
        {
            return 0.0;
            
        }
        CGFloat currentPlayedTime = _audioController.stream.currentTimePlayed.minute * 60 + _audioController.stream.currentTimePlayed.second;
        //        NSLog(@"online played time %f",currentPlayedTime);
        return currentPlayedTime/self.durationPreview;
    }
    else
    {
        if(fabs(self.duration) < 1e-6)
        {
            return 0.0;
        }
        
        
        return _audioPlayer.currentTime / self.durationPreview;
        
    }
}


-(CGFloat) currentPlayedProgress
{
    
    if(!_isLocal)
    {
        if(_audioController.stream.continuous)
        {
            return 0.0;
        
        }
        CGFloat currentPlayedTime = _audioController.stream.currentTimePlayed.minute * 60 + _audioController.stream.currentTimePlayed.second;
//        NSLog(@"online played time %f",currentPlayedTime);
        return currentPlayedTime/self.duration;
    }
    else
    {
        if(fabs(self.duration) < 1e-6)
        {
            return 0.0;
        }
        
        
        return _audioPlayer.currentTime / self.duration;
    
    }
}

-(void) progressUpdateTimerFired
{
    [self postNotification:AudioPlayManagerProgressUpdated];

}

-(void) setState:(AudioPlayManagerState)state
{
    _state = state;
    
    switch (state) {
        case AudioPlayManagerStateStopped:
            [self postNotification:AudioPlayManagerStopped];
            
            break;
        case AudioPlayManagerStateError:
            [self postNotification:AudioPlayManagerError];
            break;
            
        case AudioPlayManagerStateLoading:
            [self postNotification:AudioPlayManagerLoading];
            break;
        case AudioPlayManagerStatePlaying:
            [self postNotification:AudioPlayManagerPlaying];
            break;
        case AudioPlayManagerStatePaused:
            [self postNotification:AudioPlayManagerPaused];
            break;

        default:
            break;
    }
}

#pragma mark AudioStreamNotification
#pragma mark --
- (void)audioStreamStateDidChange:(NSNotification *)notification {
    NSDictionary *dict = [notification userInfo];
    int state = [[dict valueForKey:FSAudioStreamNotificationKey_State] intValue];
    
    switch (state) {
        case kFsAudioStreamRetrievingURL:
            self.state = AudioPlayManagerStateLoading;
            break;
        case kFsAudioStreamStopped:
            self.state = AudioPlayManagerStateStopped;
            break;
        case kFsAudioStreamBuffering:
            self.state = AudioPlayManagerStateLoading;
            break;
        case kFsAudioStreamSeeking:
            self.state = AudioPlayManagerStateLoading;
            break;
        case kFsAudioStreamPlaying:
            self.state = AudioPlayManagerStatePlaying;
            break;
        case kFSAudioStreamEndOfFile:
            [self stop];
            [self postNotification:AudioPlayManagerPlayingFinished];
            break;
        case kFsAudioStreamFailed:
            //self.state = AudioPlayManagerStateError;
            break;
    }
}

- (void)audioStreamErrorOccurred:(NSNotification *)notification {
    
    self.state = AudioPlayManagerStateError;
    NSDictionary *dict = [notification userInfo];
    int errorCode = [[dict valueForKey:FSAudioStreamNotificationKey_Error] intValue];
    
    switch (errorCode) {
        case kFsAudioStreamErrorOpen:
            NSLog(@"Cannot open the audio stream");
            break;
        case kFsAudioStreamErrorStreamParse:
            NSLog(@"Cannot read the audio stream");
            break;
        case kFsAudioStreamErrorNetwork:
            NSLog(@"Network failed: cannot play the audio stream");
            break;
        default:
            NSLog(@"Unknown error occurred");
            break;
    }
}

- (void)audioStreamMetaDataAvailable:(NSNotification *)notification {
    NSDictionary *dict = [notification userInfo];
    NSDictionary *metaData = [dict valueForKey:FSAudioStreamNotificationKey_MetaData];
    NSString *streamTitle = metaData[@"StreamTitle"];
    
    NSLog(@"%@",streamTitle);
}



#pragma mark AVAudioPlayerDelegate
#pragma mark --
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    self.state = AudioPlayManagerStateStopped;
    [self postNotification:AudioPlayManagerPlayingFinished];
}

- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
    self.state = AudioPlayManagerStateError;

}

//这两个回调调用的时候，说明之前avplayer一定在播放。
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{

}

- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
{
    if(_isLocal)
    {
        [player play];
    
    }

}


@end
